package org.metasketch.editor.toolbox.advanced;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.metasketch.diagram.javafx.graphics.BaseGraphic;
import org.metasketch.diagram.javafx.graphics.BaseLink;
import org.metasketch.editor.timeline.SnapshotManager;
import org.metasketch.javafx.graphics.IJFXGraphicNode;
import org.metasketch.model.BaseModel;
import org.metasketch.model.CommonIdentified;
import org.metasketch.model.ModelChangeManager;
import org.metasketch.reflection.RefUtil;
import org.metasketch.reflection.ReflectionAnalyser;

public class ModelHandler {

	static RefUtil util = new RefUtil();

	public static void removeAllGraphics(CommonIdentified node, BaseModel model) {
		removeAllGraphics(node, model.getModelChangeManager());
	}

	public static void removeAllGraphics(CommonIdentified node,
			ModelChangeManager modelChangeManager) {
		List<IJFXGraphicNode> listeners = modelChangeManager.getListeners(node,
				IJFXGraphicNode.class);
		for (IJFXGraphicNode graphicNode : listeners) {
			graphicNode.removeFromDiagram();
		}

	}

	public static void removeFromModelForSure(CommonIdentified node,
			BaseModel model) {
		removeFromModel(node, model);
		SnapshotManager.takeSnapshot();
	}

	protected static void removeFromModel(CommonIdentified node, BaseModel model) {
		List<CommonIdentified> toDelete = model
				.removeAllReferencesFromNodes(node);

		// if (model.isMainNode(node)){
		model.removeChild(node);
		// }

		removeAllGraphics(node, model);

		// by reflection, notice what objects out deleted nodes points to, check
		// if they are main nodes or not, and remove all associated graphics
		removeChildObjects(node, model);

		// this is to delete related objects due to model dependencies declared
		// with DeleteRelated singleton
		for (CommonIdentified deletable : toDelete) {
			removeFromModel(deletable, model);
		}

	}

	private static void removeChildObjects(CommonIdentified node,
			BaseModel model) {
		List<Object> processedNodes = new ArrayList<Object>();
		removeChildObjects(node, model, processedNodes);
	}

	private static void removeChildObjects(CommonIdentified node,
			BaseModel model, List<Object> processedNodes) {

		if (processedNodes.contains(node))
			return;

		processedNodes.add(node);

		try {
			List<String> objectFields = ReflectionAnalyser
					.getObjectFieldNames(node.getClass());
			for (String string : objectFields) {
				Object value = util.getValue(node, string);

				if (value == null || !(value instanceof CommonIdentified))
					continue;

				if (model.isMainNode((CommonIdentified) value))
					continue;

				removeFromModel((CommonIdentified) value, model);
			}

			List<String> collectionFields = ReflectionAnalyser
					.getNonNativeCollections(node.getClass());
			for (String string : collectionFields) {
				Collection collection = (Collection) util
						.getValue(node, string);

				for (Object value : collection) {

					if (value == null || !(value instanceof CommonIdentified))
						continue;

					if (model.isMainNode((CommonIdentified) value))
						continue;

					removeFromModel((CommonIdentified) value, model);

				}
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
